package com.alibaba.yinan.app.executor;

import com.alibaba.yinan.client.dto.CreateAndDispatchTaskCmd;
import com.alibaba.yinan.domain.resource.ResourceAllocator;
import com.alibaba.yinan.domain.task.Task;
import com.alibaba.yinan.domain.task.enums.TaskEvent;
import com.alibaba.yinan.domain.task.event.TaskEventPublisher;
import com.alibaba.yinan.domain.task.factory.TaskFactory;
import com.alibaba.yinan.domain.task.service.lifecycle.TaskStateMachineHandler;
import com.alibaba.yinan.domain.task.service.policy.DispatchPolicySelector;
import com.alibaba.yinan.domain.task.service.strategy.TaskStrategySelector;
import com.alibaba.yinan.domain.task.service.validator.DispatchValidatorChain;
import com.alibaba.yinan.domain.execution.executor.TaskExecuteManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 任务创建并分发执行（整合资源分配 + 异步 + 重试 + 幂等）
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TaskCreateAndDispatchCmdExe {

    private final DispatchValidatorChain validatorChain;
    private final DispatchPolicySelector policySelector;
    private final TaskStrategySelector strategySelector;
    private final TaskStateMachineHandler stateHandler;
    private final TaskEventPublisher eventPublisher;
    private final TaskExecuteManager taskExecutor;
    private final ResourceAllocator resourceAllocator;

    /**
     * 最大重试次数，可配置
     */
    private final int maxRetry = 3;

    public void execute(CreateAndDispatchTaskCmd cmd) {
        // 1. 构建聚合根
        Task task = TaskFactory.create(cmd);

        // 2. 校验
        task.validateBeforeDispatch(validatorChain);

        // 3. 类型行为定制
        task.customizeByType(strategySelector.select(task.getType()));

        // 4. 调度策略选择设备
        task.assignDevice(cmd.getDispatchPolicyKeys(), policySelector);

        // 5. 资源分配
        resourceAllocator.allocateTaskSlots(task);

        // 6. 下发状态流转
        task.changeState(TaskEvent.DISPATCH, stateHandler);

        // 7. 异步执行任务（线程池 + 幂等 + 重试 + 资源释放）
        taskExecutor.executeAsync(task, maxRetry);

        // 8. 发布任务已下发事件（可用于日志/前端推送等）
        eventPublisher.publish(task, "DISPATCHED");

        log.info("任务 {} 已成功分发并提交执行", task.getId());
    }
}
